跳到主要内容

1.4.1 Always块(组合逻辑)

数字电路由逻辑门和连线组成,任何电路都可以通过模块和assign语句的某种组合来表达。然而,有时这并不是描述电路最方便的方式。过程(其中always块是一个例子)为描述电路提供了另一种语法。

对于硬件综合来说,有两种类型的always块是相关的:

  • 组合逻辑:always @(*)
  • 时钟控制:always @(posedge clk)

组合逻辑always块等同于assign语句,因此任何组合逻辑电路都可以用这两种方式中的任意一种来表达。选择使用哪一种主要取决于哪种语法更方便。过程块内的代码语法与外部代码不同。过程块拥有更丰富的语句集(如if-then、case),不能包含连续赋值,但也引入了许多非直观的错误方式。(*过程中的连续赋值确实存在,但与连续赋值略有不同,并且不可综合。)

例如,assign语句和组合逻辑always块描述的是同一个电路。两者都创建了相同的组合逻辑块。当任何输入(右侧)值变化时,两者都会重新计算输出。

assign out1 = a & b | c ^ d;
always @(*) out2 = a & b | c ^ d;

alt text

对于组合逻辑always块,始终使用( * )作为敏感列表。显式列出信号容易出错(如果遗漏了一个),并且在硬件综合时会被忽略。如果你明确指定了敏感列表并遗漏了一个信号,综合出的硬件仍会表现得好像使用了( * ),但是仿真结果将不会匹配硬件的行为。(在SystemVerilog中,使用always_comb。)

关于wire与reg的一点说明:assign语句的左侧必须是网线类型(如wire),而在always块中的过程赋值(procedural assignment)左侧必须是变量类型(如reg)。这些类型(wire与reg)与综合出的硬件无关,只是Verilog作为硬件仿真语言使用时遗留下来的语法。

实践练习:

使用assign语句和组合逻辑always块各构建一个与门。(由于assign语句和组合逻辑always块功能相同,无法强制要求你同时使用两种方法。但你在这里是为了练习,对吧?...)

模块声明

// synthesis verilog_input_version verilog_2001
module top_module(
input a,
input b,
output wire out_assign,
output reg out_alwaysblock
);

做题区